import React from 'react'
import BaseComp from "../Base/BaseComp";
import PropTypes from "prop-types";
import {forEach, forIn, isEmpty, isFunction, isString, isUndefined, keys, pick} from "lodash-es";
import {getStorage, isObjectValEqual, removeStorage, setStorage, loadScript, getRandomKey} from "jh-utils";
import {Button, Progress} from "antd";
import {taskResultApi} from "../Config/GlobalApi";
import TaskStatus from './TaskStatus'
import TaskFailCauseModal from "./TaskFailCauseModal";
import styles from "./index.module.less"
import {connect} from "dva";

const lang = window.localStorage.getItem('umi_locale') || 'zh-CN';
const staticProps = {
    /**
     * 本地缓存的 key。
     * storageKey 和 （taskGroup+statusKey） ，必须传入其一
     */
    storageKey: PropTypes.string,
    taskGroup: PropTypes.string,
    statusKey: PropTypes.string,
    /**
     * 总的步数
     */
    totalStep: PropTypes.number,
    /**
     * 步骤描述。
     *  与 stepFunc 作用一样。权重 stepFunc > stepObj
     * 例如：
     ```
     {
            's_1': '正在注册默认应用',
            's_2': '正在创建管理员',
            's_3': () => func(),
            's_4': '完成',
          }
     ```
     */
    stepObj: PropTypes.object,
    /**
     * 根据 step 和 status 格式化步骤描述的方法。
     *  与 stepObj 作用一样。权重 stepFunc > stepObj
     * @param step
     * @param status
     * @return {string}
     */
    stepFunc: PropTypes.func,
    /**
     * 任务没开始时的默认提示语
     */
    placeholder: PropTypes.any,
    /**
     * 任务提示的前缀
     */
    prefixTip: PropTypes.string,
    /**
     * 每当任务状态有变时，回调此函数
     * @param status {number} 表示此时的任务状态：
     *      <= 1 (执行中)
     *      === 2（执行成功）
     *      > 2 （执行失败）
     */
    onChange: PropTypes.func
};

/**
 * 异步任务进度条
 */
@connect(({global})=>({
    taskGroupData: global && global.taskGroupData || []
}))
export default class TaskProgress extends BaseComp {

    static propTypes = {
        ...BaseComp.propTypes,
        ...staticProps
    };

    /**
     * 轮询定时器
     * @type {number|null}
     */
    resultTimer = null;

    moreCommonProps() {
        return [...super.moreCommonProps(), ...keys(staticProps)];
    }

    initState(props) {
        return {
            ...super.initState(props),
            loading: false,
            isRunning: false, // 是否正在轮询异步任务
            result: {
                status: 0,
                // statusKey: '',
                // step: 0,
                // taskGroup: ''
            },
            isShowFail: false, // 是否显示错误弹框
        };
    }

    componentDidMount() {
        super.componentDidMount();
        this.fetchTipConfig();
    }

    componentDidUpdate(prevProps, prevState) {
        if (!isObjectValEqual(this.props, prevProps, ['storageKey', 'taskGroup', 'statusKey','taskGroupData'])) {
            this.initResult();
        }
    }

    componentWillUnmount() {
        super.componentWillUnmount();
    }

    fetchTipConfig(){
        if(!window.taskInfoConfig){
            loadScript('/3rd/config/taskInfoConfig.js',rsp => {
                // 请求 任务国际化步骤配置
                this.setState({randomKey:getRandomKey()},()=>{
                    this.initResult();
                })
            })
        }else {
            this.initResult();
        }
    }

    initResult() {
        const {storageKey, taskGroup, statusKey} = this.props;
        let actingRecord = getStorage(storageKey);
        console.log('initResult>>>:', actingRecord);

        // 如果有缓存，则根据缓存，继续轮询任务状态
        if (actingRecord && actingRecord.statusKey) {
            this.setState({isRunning: true});
            this.fetchInitResult(pick(actingRecord, ['statusKey', 'taskGroup']));

        } else if (taskGroup && statusKey) {
            this.setState({isRunning: true});
            // 如果没有缓存，则发起新的轮询
            this.fetchInitResult({taskGroup, statusKey});
        } else {
            this.setState({isRunning: false});
        }
    }

    /**
     * 轮询异步任务的状态
     * @return {Promise<void>|*}
     */
    fetchInitResult({taskGroup, statusKey}) {
        const {storageKey, onChange, taskGroupData} = this.props;

        // if (storageKey && isEmpty(getStorage(storageKey))) {
        //     setStorage(storageKey, {statusKey, taskGroup});
        // }

        if (!isEmpty(taskGroupData)){
            let rspData = null;
            forEach(taskGroupData,task => {
                if(task.statusKey === statusKey && taskGroup === task.taskGroup){
                    rspData = {...task}
                }
            });
            if(rspData){
                let resStatus = rspData.status;
                //  // 当 已完成、错误或取消 时，删除缓存，停止轮询
                if (2 <= resStatus || TaskStatus.EXCEPTION == resStatus) {
                    removeStorage(storageKey); // 清除缓存

                } else { // 当 未执行、执行中 时，轮询获取异步任务结果
                    if(storageKey){
                        setStorage(storageKey, rspData); // 更新缓存
                    }
                }
                this.setState({
                    result: rspData,
                    isRunning: true
                });

                if (isFunction(onChange)) {
                    onChange(resStatus, rspData);
                }
            }
        }

        /**
         * return this.request(taskResultApi, {taskGroup, statusKey}).then(rsp => {

            if (rsp && 200 == rsp.status && rsp.data) {
                let rspData = {...rsp.data};
                let resStatus = rspData.status;

                //  // 当 已完成、错误或取消 时，删除缓存，停止轮询
                if (2 <= resStatus || TaskStatus.EXCEPTION == resStatus) {
                    removeStorage(storageKey); // 清除缓存

                    if (TaskStatus.COMPLETE == resStatus) { // 已完成
                        clearTimeout(this.resultTimer);
                    }

                } else { // 当 未执行、执行中 时，轮询获取异步任务结果
                    setStorage(storageKey, rspData); // 更新缓存

                    clearTimeout(this.resultTimer);
                    this.resultTimer = setTimeout(() => {
                        this.fetchInitResult({statusKey, taskGroup}).then(r => {
                        });
                    }, 3000);
                }

                this.setState({
                    result: rspData,
                    isRunning: true
                });

                if (isFunction(onChange)) {
                    onChange(resStatus, rspData);
                }
            }

            return rsp;
        });
         **/
    }

    /**
     * 查询 任务是否存在, 通知后端推送 消息
     */
    // fetchSend(taskGroup, statusKey){
    // if(taskGroup && statusKey){
    //     this.reqGet(`/api/async/prolonged_task/result?taskGroup=${taskGroup}&statusKey=${statusKey}`).then(res=>{});
    // }
    // }

    isTaskFail() {
        let {result} = this.state;
        return (2 <= result.status || -99 === result.status)
            && result.statusKey && result.writeFailCause && result.fails > 0
    }

    /**
     * 获取进度相关数据
     * @return {{tip: string, percent: number, status: string} | boolean}
     */
    getProgressObj() {
        let {result, isRunning} = this.state;
        if (!isRunning) return false;

        // let {totalStep, stepObj, stepFunc} = this.props;
        let stepObj = {}, stepFunc = null;
        // let prefixTip = this.props.prefixTip || '';
        let status = result.status; // 任务状态
        let errTxt = ""; // 错误信息
        let step = parseInt(result.step) || 0; // 当前步骤
        let tStep = 1; // 步骤总数
        let stepTip; // 步骤描述
        let progressTip = '';
        let progressPercent;
        let progressStatus;
        let desc = "";// 任务 名称描述

        // 任务 步骤国际化配置
        if(result && window.taskInfoConfig && window.taskInfoConfig[result.taskGroup]){
            let task = window.taskInfoConfig[result.taskGroup];
            if(task && task.desc && task.desc[lang]){
                desc = task.desc[lang] ? `【${task.desc[lang]}】` : '';
            }
            if(task && !isEmpty(task.step)){
                forIn(task.step,(val, key) =>{
                    if(val){
                        stepObj[key] = val[lang] || ""
                    }

                })

            }
        }
        if (!isEmpty(stepObj)) {
            tStep = keys(stepObj).length;
        }
        // if (totalStep > 0) {
        //     tStep = parseInt(totalStep);
        // } else if (isStepObj) {
        //     tStep = keys(stepObj).length;
        // }

        // 百分比
        if (status === TaskStatus.COMPLETE) {
            progressPercent = 100;
            progressStatus = 'success';
        } else {
            progressPercent = Math.floor((step > 0 ? step : 0.1) / tStep * 1000) / 10;
            progressStatus = 'active';
        }

        if (status === TaskStatus.CANCEL) {
            errTxt = this.myFormatMessage('taskP.cancel');
        } else if (status === TaskStatus.FAILURE) {
            errTxt = this.myFormatMessage('taskP.fail');
        } else if (status === TaskStatus.TIMEOUT) {
            errTxt = this.myFormatMessage('taskP.timeout');
        } else if (status === TaskStatus.EXCEPTION) {
            errTxt = this.myFormatMessage('taskP.fail') + `代码：${TaskStatus.EXCEPTION}。`;
        }

        if (!isEmpty(errTxt)) { // 如果任务出错，则提示错误信息
            let errMsg = '';

            if (isString(result.failMessage) && result.failMessage.length > 0) {
                // failMessage: "java.util.concurrent.ExecutionException: com.jianhui.exceptions.AfcRuntimeException: 不能重复执行初始化操作！"
                let failMsg = result.failMessage;
                let tmpStr = 'AfcRuntimeException';
                errMsg = failMsg.substring(failMsg.indexOf(tmpStr) + tmpStr.length + 1);

            }
            if (!isUndefined(result.count)) {
                // 'taskP.cntTip': '共【{count}】行，成功【{success}】行，失败【{fails}】行。',
                errMsg = errMsg + this.myFormatMessage('taskP.cntTip', {
                    count: result.count || 0, success: result.success || 0, fails: result.fails || 0
                });
            }
            progressTip = `${tStep > 1 ? '(步骤' + step + ')' : ''}${errTxt}${errMsg}`;
            progressPercent = 100;
            progressStatus = 'exception';

        } else { // 任务没出错，则显示对应的步骤描述

            if (!isEmpty(stepObj)) {
                stepTip = stepObj[`${step}`];
                if (isFunction(stepTip)) stepTip = stepTip();
            }

            if (!isEmpty(stepTip)) {
                progressTip = stepTip;

            } else { // 没有自定义的步骤描述，则使用默认的描述
                if (status === TaskStatus.COMPLETE) {
                    // 'taskP.done': '完成。',
                    progressTip = this.myFormatMessage('taskP.done');
                    if (result.count) {
                        progressTip += this.myFormatMessage('taskP.cntTip', {
                            count: result.count || 0, success: result.success || 0, fails: result.fails || 0
                        });
                    }
                } else if (status === TaskStatus.RUNNING) {
                    // 'taskP.running': '执行中...',
                    progressTip = this.myFormatMessage('taskP.running');
                }
            }
        }
        return {
            tip: `${desc}${progressTip}`,
            status: progressStatus,
            percent: progressPercent,
        };
    }

    hdlClickProgress() {
        if (this.isTaskFail()) {
            this.setState({isShowFail: true});
        }
    }

    stop() {
        const {storageKey, onChange, taskGroup, statusKey} = this.props;
        this.fetchStop(taskGroup, statusKey);
        removeStorage(storageKey); // 清除缓存
        this.setState({
            loading: false,
            isRunning: false,
            result: {
                status: 0,
            },
            isShowFail: false,
        });
        if (onChange) {
            onChange(-99, {
                status: -99,
                data: null
            });
        }
    }

    /**
     * 请求接口 停止任务， 广播 不再推送
     */
    fetchStop(taskGroup, statusKey){
        // console.log("停止: ",taskGroup, statusKey);
        if(taskGroup && statusKey){
            this.reqGet(`/api/async/prolonged_task/stop?taskGroup=${taskGroup}&statusKey=${statusKey}`).then(res=>{
                if(res && res.status == 200){
                    let { onStop } = this.props;
                    if(isFunction(onStop)){
                        onStop({taskGroup, statusKey})
                    }
                    // 删除 仓库数据
                    if(window.parent && isFunction(window.parent.delTaskByStatusKey)){
                        window.parent.delTaskByStatusKey({taskGroup, statusKey})
                    }
                    if(isFunction(window.delTaskByStatusKey)) {
                        window.delTaskByStatusKey({taskGroup, statusKey})
                    }
                }
            })
        }
    }

    mainRender(context) {
        let {placeholder} = this.props;
        let progressProps = {};
        let progressTip = placeholder || '';

        let obj = this.getProgressObj();
        if (obj) {
            if (obj.tip) progressTip = obj.tip;
            if (obj.percent) progressProps.percent = obj.percent;
            if (obj.status) progressProps.status = obj.status;
        }

        return (
            <div>
                <div role={'button'} onClick={this.hdlClickProgress.bind(this)}>
                    {progressTip}
                    {this.isTaskFail() && (
                        <span style={{cursor: 'pointer', display: 'inline-block'}}
                              className={'text-danger'}>{this.myFormatMessage('taskF.tl')}>></span>
                    )}
                </div>
                <div className={styles.progress}>
                    <Progress size={'large'} {...progressProps} onClick={this.hdlClickProgress.bind(this)}/>
                    {
                        (obj && obj.status == 'active') &&
                        <span
                            style={{color:'#e65b4e',width: "32px",cursor: "pointer"}}
                            onClick={this.stop.bind(this)}
                        >
                            {this.formatMsgByCn('停止')}
                        </span>
                    }
                </div>
                {
                    this.state.isShowFail && (
                        <TaskFailCauseModal
                            appins={this.props.appins}
                            statusKey={this.state.result.statusKey}
                            taskGroup={this.state.result.taskGroup}
                            // failCauseType={this.state.result.failCauseType}
                            visible={this.state.isShowFail}
                            onCancel={() => this.setState({isShowFail: false})}
                        />
                    )
                }
            </div>
        )
    }
}